feat(mock): extend output.mock with multi-generator support for msw and faker - #3407
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds plural mocks configuration (per-generator MSW/Faker), a Faker generator, core type/option normalization, refactors writers to emit per-generator mock files and indices, updates mock dispatch and utilities, and regenerates docs, samples, and tests. ChangesPlural mocks config and per-generator emission
Sequence Diagram(s)sequenceDiagram
participant User as User Config
participant Normalize as Orval Normalize
participant Generator as Generator Dispatch
participant Writers as File Writers
User->>Normalize: provide `mocks` / `mock.generators`
Normalize->>Generator: normalized generators list
Generator->>Writers: operations + mockOutputs (per type)
Writers->>Writers: per-generator file/indices assembly
Writers->>Writers: collapse inline Faker when MSW present
Writers->>User: written files (*.msw.ts, *.faker.ts, index.<ext>.ts)
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Possibly related issues
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
✨ Finishing Touches🧪 Generate unit tests (beta)
|
dc4d801 to
095c898
Compare
melloware
left a comment
There was a problem hiding this comment.
@jakiestfu sorry but can you keep it sinular mock not mocks for backward compat so 90% of people who have mock: true will get their expected out.
I think its OK its not plural its configuring mock generation
|
@melloware CC @haydencrain @ingvaldlorentzen I know there is some sticker shock in this PRs delta, but I've reviewed the code myself in Thoughts? Feedback? |
|
so I gave you one thought about about leaving it |
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
docs/content/docs/guides/client-with-zod.mdx (1)
51-59:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winIncomplete file structure documentation.
The generated files section shows only
pets.msw.ts(line 55), but according to the PR objectives,mocks: trueemits both MSW and Faker files. The documentation should also listpets.faker.tsto reflect the actual output.📝 Suggested addition to file structure
src/api/ ├── endpoints/ │ └── pets/ │ ├── pets.ts # SWR hooks │ ├── pets.msw.ts # MSW mocks +│ ├── pets.faker.ts # Faker mocks │ └── pets.zod.ts # Zod schemas └── models/ └── ...🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/content/docs/guides/client-with-zod.mdx` around lines 51 - 59, The docs show only pets.msw.ts under src/api/endpoints/pets but the generator also emits Faker files when mocks: true; update the file structure example to include pets.faker.ts alongside pets.msw.ts (keeping pets.ts and pets.zod.ts) so it accurately reflects the output; edit the snippet that lists src/api/endpoints/pets to add an entry for pets.faker.ts and ensure ordering/notes match the existing style.docs/content/docs/guides/basics.mdx (1)
40-40:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winUpdate table to reference
mocksinstead ofmock.The configuration example on line 21 correctly uses
mocks: true, but this table row still references the oldmockkey, creating an inconsistency in the documentation.📝 Proposed fix
-| `mock` | Generates mocks with MSW. See the [MSW guide](/docs/guides/msw) | +| `mocks` | Generates mocks with MSW. See the [MSW guide](/docs/guides/msw) |🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/content/docs/guides/basics.mdx` at line 40, Update the table row that currently references the configuration key `mock` to use `mocks` so it matches the example earlier (`mocks: true`); locate the table cell containing the backticked `mock` symbol and replace it with `mocks` (keeping the MSW guide link and surrounding text unchanged) to remove the inconsistency.
🧹 Nitpick comments (7)
packages/mock/src/faker/index.test.ts (1)
74-81: ⚡ Quick winStrengthen the equivalence assertion to match the test intent.
This test currently validates only that
implementation.functionis a string, not that it matches the MSW output as the title/comment claims. Compare against the MSW-generated function string directly to actually guard behavior.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/mock/src/faker/index.test.ts` around lines 74 - 81, The test currently only asserts typeof fakerResult.implementation.function is 'string' but should verify equivalence to the MSW output; call generate with OutputMockType.MSW (e.g., const mswResult = generate({ mock: { type: OutputMockType.MSW } })) and assert that fakerResult.implementation.function === mswResult.implementation.function so the faker generator truly matches MSW's emitted function string; reference the generate function, OutputMockType, fakerResult, mswResult, and implementation.function when making the change.samples/svelte-query/basic/__snapshots__/endpoints/petstoreFromFileSpecWithTransformer.faker.ts (2)
21-26: ⚡ Quick winRemove unnecessary IIFE wrappers.
The outer
(() => ({ ... }))()wrapper serves no purpose here and can be removed for cleaner generated code.♻️ Simplified function
-export const getShowPetByIdResponseMock = () => - (() => ({ - id: faker.number.int({ min: 1, max: 99 }), - name: faker.person.firstName(), - tag: faker.helpers.arrayElement([faker.string.sample(), undefined]), - }))(); +export const getShowPetByIdResponseMock = () => ({ + id: faker.number.int({ min: 1, max: 99 }), + name: faker.person.firstName(), + tag: faker.helpers.arrayElement([faker.string.sample(), undefined]), +});🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@samples/svelte-query/basic/__snapshots__/endpoints/petstoreFromFileSpecWithTransformer.faker.ts` around lines 21 - 26, The function getShowPetByIdResponseMock contains an unnecessary immediately-invoked function expression (IIFE) wrapper around the returned object; remove the outer (() => ({ ... }))() and have getShowPetByIdResponseMock directly return the object literal (id, name, tag) so the code is simpler and functionally identical.
11-19: ⚡ Quick winSimplify Array.from mapper to avoid creating unused sequential values.
The current pattern creates an array
[1, 2, 3, ..., N]viaArray.from({ length }, (_, i) => i + 1), but the subsequent.map()immediately discards these values. The mapper inArray.fromcan directly create the final objects.♻️ Simplified array generation
export const getListPetsResponseMock = (): Pets => Array.from( { length: faker.number.int({ min: 1, max: 10 }) }, - (_, i) => i + 1, - ).map(() => ({ + ).map(() => ({ id: (() => faker.number.int({ min: 1, max: 99999 }))(), name: (() => faker.person.lastName())(), tag: (() => faker.person.lastName())(), }));Or use the mapper directly:
export const getListPetsResponseMock = (): Pets => Array.from( { length: faker.number.int({ min: 1, max: 10 }) }, + () => ({ + id: faker.number.int({ min: 1, max: 99999 }), + name: faker.person.lastName(), + tag: faker.person.lastName(), + }), - (_, i) => i + 1, - ).map(() => ({ - id: (() => faker.number.int({ min: 1, max: 99999 }))(), - name: (() => faker.person.lastName())(), - tag: (() => faker.person.lastName())(), - })); + );🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@samples/svelte-query/basic/__snapshots__/endpoints/petstoreFromFileSpecWithTransformer.faker.ts` around lines 11 - 19, The getListPetsResponseMock function builds a sequential array then immediately maps over it to create pet objects; change Array.from({ length: faker.number.int(...) }, (_, i) => i + 1).map(...) to use Array.from({ length: faker.number.int(...) }, () => ({ id: faker.number.int({ min: 1, max: 99999 }), name: faker.person.lastName(), tag: faker.person.lastName() })) so the mapper directly returns the pet objects and you can remove the extra .map().samples/svelte-query/basic/src/api/endpoints/petstoreFromFileSpecWithTransformer.faker.ts (2)
11-19: ⚡ Quick winSimplify Array.from mapper to avoid creating unused sequential values.
The current pattern creates an array
[1, 2, 3, ..., N]viaArray.from({ length }, (_, i) => i + 1), but the subsequent.map()immediately discards these values. The mapper inArray.fromcan directly create the final objects.♻️ Simplified array generation
export const getListPetsResponseMock = (): Pets => Array.from( { length: faker.number.int({ min: 1, max: 10 }) }, - (_, i) => i + 1, - ).map(() => ({ + ).map(() => ({ id: (() => faker.number.int({ min: 1, max: 99999 }))(), name: (() => faker.person.lastName())(), tag: (() => faker.person.lastName())(), }));Or even better, use the mapper directly:
export const getListPetsResponseMock = (): Pets => Array.from( { length: faker.number.int({ min: 1, max: 10 }) }, + () => ({ + id: faker.number.int({ min: 1, max: 99999 }), + name: faker.person.lastName(), + tag: faker.person.lastName(), + }), - (_, i) => i + 1, - ).map(() => ({ - id: (() => faker.number.int({ min: 1, max: 99999 }))(), - name: (() => faker.person.lastName())(), - tag: (() => faker.person.lastName())(), - })); + );🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@samples/svelte-query/basic/src/api/endpoints/petstoreFromFileSpecWithTransformer.faker.ts` around lines 11 - 19, The getListPetsResponseMock function builds an intermediate numeric array then maps it away; replace the two-step Array.from(...).map(...) with a single Array.from call that creates the pet objects directly (e.g., Array.from({ length: faker.number.int({ min: 1, max: 10 }) }, () => ({ id: faker.number.int({ min: 1, max: 99999 }), name: faker.person.lastName(), tag: faker.person.lastName() }))). Update getListPetsResponseMock to use this direct mapper so there are no unused sequential values.
21-26: ⚡ Quick winRemove unnecessary IIFE wrappers.
The outer
(() => ({ ... }))()wrapper and individual property IIFEs serve no purpose here and can be removed for cleaner generated code.♻️ Simplified function
-export const getShowPetByIdResponseMock = () => - (() => ({ - id: faker.number.int({ min: 1, max: 99 }), - name: faker.person.firstName(), - tag: faker.helpers.arrayElement([faker.string.sample(), undefined]), - }))(); +export const getShowPetByIdResponseMock = () => ({ + id: faker.number.int({ min: 1, max: 99 }), + name: faker.person.firstName(), + tag: faker.helpers.arrayElement([faker.string.sample(), undefined]), +});🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@samples/svelte-query/basic/src/api/endpoints/petstoreFromFileSpecWithTransformer.faker.ts` around lines 21 - 26, The getShowPetByIdResponseMock function uses an unnecessary outer IIFE (and individual property IIFEs per the review); replace the outer wrapper by returning the object literal directly from the arrow function and ensure each property calls faker directly (i.e., change export const getShowPetByIdResponseMock = () => (() => ({ ... }))() to export const getShowPetByIdResponseMock = () => ({ id: faker.number.int(...), name: faker.person.firstName(), tag: faker.helpers.arrayElement([...]) }); so there are no self-invoking functions around the object or its properties.samples/react-app/__snapshots__/endpoints/petstoreFromFileSpecWithTransformer.faker.ts (2)
11-19: ⚡ Quick winSimplify Array.from mapper to avoid creating unused sequential values.
The current pattern creates an array
[1, 2, 3, ..., N]viaArray.from({ length }, (_, i) => i + 1), but the subsequent.map()immediately discards these values. The mapper inArray.fromcan directly create the final objects.♻️ Simplified array generation
export const getListPetsResponseMock = (): Pets => Array.from( { length: faker.number.int({ min: 1, max: 10 }) }, - (_, i) => i + 1, - ).map(() => ({ + ).map(() => ({ id: (() => faker.number.int({ min: 1, max: 99999 }))(), name: (() => faker.person.lastName())(), tag: (() => faker.person.lastName())(), }));Or use the mapper directly:
export const getListPetsResponseMock = (): Pets => Array.from( { length: faker.number.int({ min: 1, max: 10 }) }, + () => ({ + id: faker.number.int({ min: 1, max: 99999 }), + name: faker.person.lastName(), + tag: faker.person.lastName(), + }), - (_, i) => i + 1, - ).map(() => ({ - id: (() => faker.number.int({ min: 1, max: 99999 }))(), - name: (() => faker.person.lastName())(), - tag: (() => faker.person.lastName())(), - })); + );🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@samples/react-app/__snapshots__/endpoints/petstoreFromFileSpecWithTransformer.faker.ts` around lines 11 - 19, The generated mock getListPetsResponseMock creates a sequential array via Array.from(..., (_, i) => i + 1) and then discards those values with a subsequent .map(); change Array.from in getListPetsResponseMock to use the mapper to directly produce each Pets object (use Array.from({ length: faker.number.int({ min: 1, max: 10 }) }, () => ({ id: faker.number.int({ min: 1, max: 99999 }), name: faker.person.lastName(), tag: faker.person.lastName() }))) so you no longer need the extra .map() and eliminate the unused sequential values.
21-26: ⚡ Quick winRemove unnecessary IIFE wrappers.
The outer
(() => ({ ... }))()wrapper serves no purpose here and can be removed for cleaner generated code.♻️ Simplified function
-export const getShowPetByIdResponseMock = () => - (() => ({ - id: faker.number.int({ min: 1, max: 99 }), - name: faker.person.firstName(), - tag: faker.helpers.arrayElement([faker.word.sample(), undefined]), - }))(); +export const getShowPetByIdResponseMock = () => ({ + id: faker.number.int({ min: 1, max: 99 }), + name: faker.person.firstName(), + tag: faker.helpers.arrayElement([faker.word.sample(), undefined]), +});🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@samples/react-app/__snapshots__/endpoints/petstoreFromFileSpecWithTransformer.faker.ts` around lines 21 - 26, The generated mock function getShowPetByIdResponseMock contains an unnecessary immediately-invoked function expression; remove the outer (() => ({ ... }))() wrapper so the function directly returns the object literal (id, name, tag) instead of invoking an IIFE—i.e., change getShowPetByIdResponseMock to return the faker-generated object directly without the extra parentheses/IIFE.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/content/docs/reference/integration.mdx`:
- Line 78: The commented example uses the old flat "mock" config; update the
comment to show the new API that wraps generator configs in a generators array
(e.g., replace the old "// mock: { type: 'msw', delay: 1000 }" example with an
explicit generators array entry such as "// generators: [{ type: 'msw', delay:
1000 }]" so the docs reflect the new explicit generator configuration
structure).
In `@packages/core/src/writers/split-tags-mode.ts`:
- Around line 58-64: The loop building indexFilePathsByType with
generatorEntries uses the mock-type extension (via
getMockFileExtensionByTypeName) as the sole key so multiple generator entries
with the same type overwrite each other; change the logic to handle duplicate
types by making the key unique per entry (e.g., include a per-entry identifier
like entry.name or entry.id) or accumulate paths per-extension
(Map<string,string[]>), and only write/initialize an index path when creating a
new unique path (or deduplicate before writing). Update the same pattern in the
other affected blocks that reference indexFilePathsByType/generatorEntries (the
other write/export loops) so all places either check for existing entries before
overwriting or switch to storing arrays of paths and iterate them when emitting
indexes.
- Around line 243-250: The loop that builds mock files silently skips
function-based generator entries (mockOutputs loop inspecting
output.mocks.generators and using isFunction), causing missing files; update the
loop in the split-tags logic (the for ... of mockOutputs.entries() block) to
detect when entry is a function and throw a clear, descriptive error (e.g.,
"Function-based mock generators are not supported in tags-split mode") instead
of continue, so callers fail fast until ClientMockBuilder functions are
implemented.
In `@packages/core/src/writers/target.ts`:
- Around line 66-71: The code incorrectly collapses multiple generator entries
by matching target.mockOutputs by type (using find) which loses per-entry
options/files; instead, for each operation.mockOutputs entry create a distinct
mock output instance rather than reusing one by type: remove the find((m) =>
m.type === opMock.type) merge, call emptyMockOutputFull(opMock.type) for each
opMock, push that new instance into target.mockOutputs, and then copy/merge the
specific per-entry fields (options/files/etc.) from operation.mockOutputs into
the newly created instance so the new output.mocks.generators model preserves
per-entry configuration.
In `@packages/mock/src/index.ts`:
- Around line 29-39: The switch in getDefaultMockOptionsForType uses case
clauses without braces which triggers unicorn/switch-case-braces; wrap each case
body in braces (e.g., case OutputMockType.FAKER: { return DEFAULT_FAKER_OPTIONS;
} ) and do the same for the other two switch statements in this file so each
case (including default) has its own block, or refactor to equivalent if/else
blocks; update getDefaultMockOptionsForType and the other switch-using functions
in the module accordingly.
---
Outside diff comments:
In `@docs/content/docs/guides/basics.mdx`:
- Line 40: Update the table row that currently references the configuration key
`mock` to use `mocks` so it matches the example earlier (`mocks: true`); locate
the table cell containing the backticked `mock` symbol and replace it with
`mocks` (keeping the MSW guide link and surrounding text unchanged) to remove
the inconsistency.
In `@docs/content/docs/guides/client-with-zod.mdx`:
- Around line 51-59: The docs show only pets.msw.ts under src/api/endpoints/pets
but the generator also emits Faker files when mocks: true; update the file
structure example to include pets.faker.ts alongside pets.msw.ts (keeping
pets.ts and pets.zod.ts) so it accurately reflects the output; edit the snippet
that lists src/api/endpoints/pets to add an entry for pets.faker.ts and ensure
ordering/notes match the existing style.
---
Nitpick comments:
In `@packages/mock/src/faker/index.test.ts`:
- Around line 74-81: The test currently only asserts typeof
fakerResult.implementation.function is 'string' but should verify equivalence to
the MSW output; call generate with OutputMockType.MSW (e.g., const mswResult =
generate({ mock: { type: OutputMockType.MSW } })) and assert that
fakerResult.implementation.function === mswResult.implementation.function so the
faker generator truly matches MSW's emitted function string; reference the
generate function, OutputMockType, fakerResult, mswResult, and
implementation.function when making the change.
In
`@samples/react-app/__snapshots__/endpoints/petstoreFromFileSpecWithTransformer.faker.ts`:
- Around line 11-19: The generated mock getListPetsResponseMock creates a
sequential array via Array.from(..., (_, i) => i + 1) and then discards those
values with a subsequent .map(); change Array.from in getListPetsResponseMock to
use the mapper to directly produce each Pets object (use Array.from({ length:
faker.number.int({ min: 1, max: 10 }) }, () => ({ id: faker.number.int({ min: 1,
max: 99999 }), name: faker.person.lastName(), tag: faker.person.lastName() })))
so you no longer need the extra .map() and eliminate the unused sequential
values.
- Around line 21-26: The generated mock function getShowPetByIdResponseMock
contains an unnecessary immediately-invoked function expression; remove the
outer (() => ({ ... }))() wrapper so the function directly returns the object
literal (id, name, tag) instead of invoking an IIFE—i.e., change
getShowPetByIdResponseMock to return the faker-generated object directly without
the extra parentheses/IIFE.
In
`@samples/svelte-query/basic/__snapshots__/endpoints/petstoreFromFileSpecWithTransformer.faker.ts`:
- Around line 21-26: The function getShowPetByIdResponseMock contains an
unnecessary immediately-invoked function expression (IIFE) wrapper around the
returned object; remove the outer (() => ({ ... }))() and have
getShowPetByIdResponseMock directly return the object literal (id, name, tag) so
the code is simpler and functionally identical.
- Around line 11-19: The getListPetsResponseMock function builds a sequential
array then immediately maps over it to create pet objects; change Array.from({
length: faker.number.int(...) }, (_, i) => i + 1).map(...) to use Array.from({
length: faker.number.int(...) }, () => ({ id: faker.number.int({ min: 1, max:
99999 }), name: faker.person.lastName(), tag: faker.person.lastName() })) so the
mapper directly returns the pet objects and you can remove the extra .map().
In
`@samples/svelte-query/basic/src/api/endpoints/petstoreFromFileSpecWithTransformer.faker.ts`:
- Around line 11-19: The getListPetsResponseMock function builds an intermediate
numeric array then maps it away; replace the two-step Array.from(...).map(...)
with a single Array.from call that creates the pet objects directly (e.g.,
Array.from({ length: faker.number.int({ min: 1, max: 10 }) }, () => ({ id:
faker.number.int({ min: 1, max: 99999 }), name: faker.person.lastName(), tag:
faker.person.lastName() }))). Update getListPetsResponseMock to use this direct
mapper so there are no unused sequential values.
- Around line 21-26: The getShowPetByIdResponseMock function uses an unnecessary
outer IIFE (and individual property IIFEs per the review); replace the outer
wrapper by returning the object literal directly from the arrow function and
ensure each property calls faker directly (i.e., change export const
getShowPetByIdResponseMock = () => (() => ({ ... }))() to export const
getShowPetByIdResponseMock = () => ({ id: faker.number.int(...), name:
faker.person.firstName(), tag: faker.helpers.arrayElement([...]) }); so there
are no self-invoking functions around the object or its properties.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 7266088c-c0b7-49a6-8ea3-09c5d22e6821
⛔ Files ignored due to path filters (7)
samples/hono/hono-with-fetch-client/next-app/app/gen/pets/pets.faker.tsis excluded by!**/gen/**samples/next-app-with-fetch/app/gen/pets/pets.faker.tsis excluded by!**/gen/**samples/react-query/custom-fetch/src/gen/pets/pets.faker.tsis excluded by!**/gen/**samples/svelte-query/custom-fetch/src/gen/pets/pets.faker.tsis excluded by!**/gen/**samples/svelte-query/v6-custom-fetch/src/gen/pets/pets.faker.tsis excluded by!**/gen/**samples/swr-with-zod/src/gen/endpoints/pets/pets.faker.tsis excluded by!**/gen/**samples/vue-query/custom-fetch/src/gen/pets/pets.faker.tsis excluded by!**/gen/**
📒 Files selected for processing (134)
docs/content/docs/guides/angular-query.mdxdocs/content/docs/guides/angular.mdxdocs/content/docs/guides/basics.mdxdocs/content/docs/guides/client-with-zod.mdxdocs/content/docs/guides/fetch.mdxdocs/content/docs/guides/msw.mdxdocs/content/docs/guides/react-query.mdxdocs/content/docs/guides/solid-query.mdxdocs/content/docs/guides/solid-start.mdxdocs/content/docs/guides/svelte-query.mdxdocs/content/docs/guides/swr.mdxdocs/content/docs/guides/vue-query.mdxdocs/content/docs/reference/configuration/full-example.mdxdocs/content/docs/reference/configuration/output.mdxdocs/content/docs/reference/integration.mdxpackages/angular/src/http-client.test.tspackages/angular/src/http-resource.test.tspackages/core/src/test-utils/context.tspackages/core/src/test-utils/split-modes.tspackages/core/src/types.tspackages/core/src/utils/assertion.tspackages/core/src/utils/file-extensions.tspackages/core/src/writers/mock-outputs.tspackages/core/src/writers/single-mode.tspackages/core/src/writers/split-mode.tspackages/core/src/writers/split-tags-mode.tspackages/core/src/writers/tags-mode.tspackages/core/src/writers/target-tags.tspackages/core/src/writers/target.tspackages/hono/src/index.tspackages/mcp/src/index.tspackages/mock/src/delay.tspackages/mock/src/faker/getters/combine.test.tspackages/mock/src/faker/index.test.tspackages/mock/src/faker/index.tspackages/mock/src/index.tspackages/mock/src/msw/index.test.tspackages/mock/src/msw/index.tspackages/orval/src/api.tspackages/orval/src/bin/orval.tspackages/orval/src/client.tspackages/orval/src/utils/options.tspackages/orval/src/write-specs.tspackages/solid-start/src/index.test.tssamples/angular-app/orval.config.tssamples/angular-query/orval.config.tssamples/basic/orval.config.tssamples/hono/hono-with-fetch-client/__snapshots__/next-app/pets/pets.faker.tssamples/hono/hono-with-fetch-client/orval.config.tssamples/next-app-with-fetch/__snapshots__/pets/pets.faker.tssamples/next-app-with-fetch/orval.config.tssamples/react-app-with-swr/basic/__snapshots__/endpoints/petstoreFromFileSpecWithTransformer.faker.tssamples/react-app-with-swr/basic/orval.config.tssamples/react-app-with-swr/basic/src/api/endpoints/petstoreFromFileSpecWithTransformer.faker.tssamples/react-app-with-swr/fetch-client/__snapshots__/endpoints/swaggerPetstore.faker.tssamples/react-app-with-swr/fetch-client/orval.config.tssamples/react-app-with-swr/fetch-client/src/api/endpoints/swaggerPetstore.faker.tssamples/react-app/__snapshots__/endpoints/petstoreFromFileSpecWithTransformer.faker.tssamples/react-app/orval.config.tssamples/react-app/src/api/endpoints/petstoreFromFileSpecWithTransformer.faker.tssamples/react-query/basic/__snapshots__/endpoints/petstoreFromFileSpecWithTransformer.faker.tssamples/react-query/basic/orval.config.tssamples/react-query/basic/src/api/endpoints/petstoreFromFileSpecWithTransformer.faker.tssamples/react-query/custom-fetch/__snapshots__/pets/pets.faker.tssamples/react-query/custom-fetch/orval.config.tssamples/solid-query/basic/orval.config.tssamples/solid-query/custom-fetch/orval.config.tssamples/solid-start/basic/orval.config.tssamples/solid-start/basic/src/api/endpoints/petstore.faker.tssamples/svelte-query/basic/__snapshots__/endpoints/petstoreFromFileSpecWithTransformer.faker.tssamples/svelte-query/basic/orval.config.tssamples/svelte-query/basic/src/api/endpoints/petstoreFromFileSpecWithTransformer.faker.tssamples/svelte-query/custom-fetch/__snapshots__/pets/pets.faker.tssamples/svelte-query/custom-fetch/orval.config.tssamples/svelte-query/v6-custom-fetch/__snapshots__/pets/pets.faker.tssamples/svelte-query/v6-custom-fetch/orval.config.tssamples/swr-with-zod/__snapshots__/endpoints/pets/pets.faker.tssamples/swr-with-zod/orval.config.tssamples/vue-query/custom-fetch/__snapshots__/pets/pets.faker.tssamples/vue-query/custom-fetch/orval.config.tssamples/vue-query/vue-query-basic/__snapshots__/endpoints/petstoreFromFileSpecWithTransformer.faker.tssamples/vue-query/vue-query-basic/orval.config.tssamples/vue-query/vue-query-basic/src/api/endpoints/petstoreFromFileSpecWithTransformer.faker.tsskills/orval/SKILL.mdskills/orval/advanced-config.mdskills/orval/angular.mdskills/orval/hono.mdskills/orval/mocking-msw.mdskills/orval/solid-start.mdskills/orval/tooling-workflow.mdtests/__snapshots__/angular/split/endpoints.faker.tstests/__snapshots__/angular/tags-split/health/health.faker.tstests/__snapshots__/angular/tags-split/pets/pets.faker.tstests/__snapshots__/axios/petstore-tags-split-mutator/health/health.faker.tstests/__snapshots__/axios/petstore-tags-split-mutator/pets/pets.faker.tstests/__snapshots__/axios/petstore-tags-split/health/health.faker.tstests/__snapshots__/axios/petstore-tags-split/pets/pets.faker.tstests/__snapshots__/axios/split/endpoints.faker.tstests/__snapshots__/default/issue-2998/documents/documents.faker.tstests/__snapshots__/default/issue-2998/requests/requests.faker.tstests/__snapshots__/default/override-mock/endpoints.faker.tstests/__snapshots__/fetch/petstore-tags-split/health/health.faker.tstests/__snapshots__/fetch/petstore-tags-split/pets/pets.faker.tstests/__snapshots__/fetch/split/endpoints.faker.tstests/__snapshots__/mock/petstore-tags-split/health/health.faker.tstests/__snapshots__/mock/petstore-tags-split/pets/pets.faker.tstests/__snapshots__/mock/split/endpoints.faker.tstests/__snapshots__/react-query/importFromSubdirectory/endpoints.faker.tstests/__snapshots__/react-query/petstore-tags-split/health/health.faker.tstests/__snapshots__/react-query/petstore-tags-split/pets/pets.faker.tstests/__snapshots__/react-query/split/endpoints.faker.tstests/__snapshots__/svelte-query/petstore-tags-split/health/health.faker.tstests/__snapshots__/svelte-query/petstore-tags-split/pets/pets.faker.tstests/__snapshots__/svelte-query/split/endpoints.faker.tstests/__snapshots__/swr/petstore-tags-split/health/health.faker.tstests/__snapshots__/swr/petstore-tags-split/pets/pets.faker.tstests/__snapshots__/swr/split/endpoints.faker.tstests/__snapshots__/vue-query/petstore-tags-split/health/health.faker.tstests/__snapshots__/vue-query/petstore-tags-split/pets/pets.faker.tstests/__snapshots__/vue-query/split/endpoints.faker.tstests/__snapshots__/zod/petstore-tags-split/pets/pets.faker.tstests/__snapshots__/zod/split/endpoints.faker.tstests/configs/angular.config.tstests/configs/axios.config.tstests/configs/default.config.tstests/configs/fetch.config.tstests/configs/mock.config.tstests/configs/react-query.config.tstests/configs/solid-query.config.tstests/configs/solid-start.config.tstests/configs/svelte-query.config.tstests/configs/swr.config.tstests/configs/vue-query.config.tstests/configs/zod.config.ts
💤 Files with no reviewable changes (3)
- packages/orval/src/api.ts
- packages/mcp/src/index.ts
- packages/hono/src/index.ts
…MockOptions union Make GlobalMockOptions a discriminated union over OutputMockType (MSW | FAKER) so consumers can narrow per-generator settings. Hoist shared fields into CommonMockOptions and move msw-only fields (baseUrl, delay, delayFunctionLazyExecute) onto MswMockOptions. Introduce OutputMocksConfig and NormalizedMocksConfig to back the new output.mocks shape (boolean | OutputMocksConfig | ClientMockBuilder), and replace output.mock / NormalizedOutputOptions.mock / GlobalOptions.mock with output.mocks. GeneratorTarget(Full)/GeneratorOperation gain mockOutputs arrays keyed by mock type so writers can emit one file per configured generator. Drive getMockFileExtensionByTypeName from mock.type so each entry's filename suffix (.msw.ts, .faker.ts) matches its configured generator. Remove the GlobalMockOptions.generateHandlers flag - omitting an MSW generator entry now expresses the same intent.
Add packages/mock/src/faker/index.ts exposing generateFaker and generateFakerImports. The faker generator reuses the MSW response-factory output and strips the handler payload so it can emit a standalone <file>.faker.ts with no msw dependency. Replace DEFAULT_MOCK_OPTIONS with per-type DEFAULT_MSW_OPTIONS / DEFAULT_FAKER_OPTIONS plus a getDefaultMockOptionsForType helper used by the normalizer. The top-level generateMock and generateMockImports now dispatch on OutputMockType so each entry in output.mocks.generators is routed to the correct generator. Narrow GlobalMockOptions via isMswMock in delay.ts and msw/index.ts so msw-only fields (delay, baseUrl, delayFunctionLazyExecute) are no longer read off faker entries. Drop the generateHandlers branch from generateMSW and getMSWDependencies.
Replace the singular implementationMock / importsMock fields on
GeneratorTarget(Full) and GeneratorOperation with GeneratorMockOutput arrays
keyed by OutputMockType. target.ts and target-tags.ts accumulate one
GeneratorMockOutputFull per generator entry, applying the header/footer
handler wrapper only to entries that produced handler aggregator output
(so faker-only entries stay handler-free).
Writers now iterate target.mockOutputs and emit a separate file per entry.
split-mode and split-tags-mode use getMockFileExtensionByTypeName(entry) for
the per-file suffix (.msw.ts / .faker.ts). single-mode and tags-mode still
inline the mocks into the implementation file but call importsMock once per
entry so each entry's import header reflects its own generator.
split-tags-mode pre-creates one index.<ext>.ts per generator when
output.mocks.indexMockFiles is true. MSW entries keep the named-aggregator
re-export shape (export { getTagMock } from ...) so existing
index.msw.ts consumers keep working; faker entries use export * since
faker has no aggregator handler.
Update test-utils fixtures (createSplitModeOperation, createTestContextSpec)
to use the new mocks shape and mockOutputs array.
Rework normalizeOptions to coerce the new output.mocks shape (boolean, ClientMockBuilder, or OutputMocksConfig) into a NormalizedMocksConfig with indexMockFiles and a generators array of GlobalMockOptions or ClientMockBuilder. The mocks: true shorthand expands to the default MSW plus default Faker generators. Replace the singular generateMock in client.ts with invokeMockGenerator and let generateOperations call it once per configured generator, populating GeneratorOperation.mockOutputs with one entry per generator. Drop the handlersDisabled branch from the client header/footer/title helpers; the same intent is now expressed by omitting an msw entry from generators. Update write-specs to filter out generated mock files by all configured extensions (msw, faker, ...) when assembling the workspace index. Drop the redundant mock field from api.ts, hono, and mcp pipelines since each entry is now threaded through invokeMockGenerator individually. Rename the CLI flag from --mock to --mocks to match the new option name.
Update hono, mcp, angular, and solid-start callers/tests for the new
NormalizedOutputOptions shape. The hono and mcp zod-generation paths no
longer pre-thread mock into GeneratorOptions (per-entry routing is handled
by invokeMockGenerator). Test fixtures across angular, solid-start, and
the faker combine suite move to the canonical
mocks: { indexMockFiles: false, generators: [] } default.
Drop the generateHandlers: false describe block from msw/index.test.ts
since that mode is replaced by omitting an msw entry from
output.mocks.generators.
Migrate every top-level output.mock declaration across tests/configs and
samples/** to the new output.mocks shape. Boolean shorthand (mock: true)
becomes mocks: true. Object form (mock: { type, ... }) is rewritten as
mocks: { generators: [{ type, ... }] }, with indexMockFiles hoisted onto
the mocks object. The CLI custom-builder example uses the function-form
mocks: (verbOptions, _) => ... shorthand.
Per-operation override.mock and override.operations.X.mock entries keep
their existing per-operation shape; only the top-level output.mock is
renamed.
…nd add v8 migration note - Rename mocks: → mock: in all code examples across guides and reference docs - Update ## mocks section heading to ## mock in output.mdx - Fix stale comment in integration.mdx (old single-generator shape → generators array) - Add pets.faker.ts to file tree in client-with-zod.mdx (mock: true emits both files) - Add output.mock shape change to v8 breaking changes guide (section 10) - Throw on function mock generators in tags-split mode instead of silently skipping
Validates that each mock type (msw, faker) appears at most once in mock.generators. Duplicate entries would produce conflicting file outputs, so we fail fast with a clear error message. Also removes an unnecessary nullish coalescing on the required generators field (lint: @typescript-eslint/no-unnecessary-condition).
4eb10c6 to
74fe6d6
Compare
|
@melloware Restored |
There was a problem hiding this comment.
Actionable comments posted: 7
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/content/docs/guides/msw.mdx`:
- Line 243: Update the docs text to correct the config key typo: replace the
incorrect `mocks.indexMockFiles` reference with the actual option path
`output.mock.indexMockFiles` so the sentence reads that enabling
`output.mock.indexMockFiles` emits a root-level `index.<ext>.ts` (e.g.,
`index.msw.ts`) for each generator entry in `tags-split` mode.
In `@packages/angular/src/http-client.test.ts`:
- Line 49: The test fixture uses the wrong property name: change the object key
from "mocks" to "mock" in the normalized output fixture so it matches the
NormalizedOutputOptions shape and ensures output.mock is defined in generator
tests; locate the fixture object (where "mocks: { indexMockFiles: false,
generators: [] }" is declared in http-client.test.ts) and rename the key to
"mock" while keeping the inner structure the same.
In `@packages/angular/src/http-resource.test.ts`:
- Line 57: The test uses the wrong property name "mocks" in the normalized
output defaults (mocks: { indexMockFiles: false, generators: [] }), which should
be "mock"; update the property key from "mocks" to "mock" in the test
configuration so the normalized output defaults correctly apply (replace the
"mocks" property with "mock" in the object containing indexMockFiles and
generators).
In `@packages/core/src/types.ts`:
- Around line 442-450: The doc comment above the OutputMocksConfig interface
refers to a top-level "mocks" key but the public option is singular "mock";
update the comment and example to use "mock" (e.g., "mock: { indexMockFiles:
true, generators: [...] }") so the documentation matches the actual option name
and ensure any inline examples and descriptive text reference OutputMocksConfig
and the singular "mock" key consistently.
In `@packages/core/src/writers/split-mode.ts`:
- Around line 170-171: The loop in split-mode.ts incorrectly pairs mockOutputs
with generators by index (for ... of mockOutputs.entries()) which can misalign;
update the lookup to find the matching generator by type instead (like
single-mode.ts and tags-mode.ts) — inside the for loop replace direct access to
output.mock.generators[index] with a search such as
output.mock.generators.find(g => g.type === mockOutput.type), handle the case
where no generator is found (fallback or skip) and then use that found
generator's options when building the mock (ensure variables like
generatorOptions or generator are updated accordingly).
In `@packages/orval/src/utils/options.ts`:
- Around line 190-194: The code assumes mocksOption.generators exists and is an
array before calling .map, causing an opaque runtime crash; update the handling
in the branch that builds mocks (where mocks, mocksOption, indexMockFiles, and
generators are referenced) to validate mocksOption.generators with Array.isArray
before mapping: if it's an array, map and use isFunction(...) as before; if it's
missing or not an array, either default to an empty array or throw a clear,
descriptive configuration error indicating that "mocks.generators" must be an
array of generator functions; ensure the rest of the mocks object
(indexMockFiles) continues to use the nullish-coalesced default as currently
implemented.
In `@packages/solid-start/src/index.test.ts`:
- Line 32: In the test configuration object in
packages/solid-start/src/index.test.ts replace the incorrect property name
"mocks" with the singular "mock" so TypeScript recognizes the correct property;
locate the object literal containing mocks: { indexMockFiles: false, generators:
[] } and rename the key to mock: { indexMockFiles: false, generators: [] }
ensuring any references in the same file or nearby tests use the new "mock" key
consistently.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 7d01f3e1-e5a0-4d2f-a383-a3852de5cc08
⛔ Files ignored due to path filters (7)
samples/hono/hono-with-fetch-client/next-app/app/gen/pets/pets.faker.tsis excluded by!**/gen/**samples/next-app-with-fetch/app/gen/pets/pets.faker.tsis excluded by!**/gen/**samples/react-query/custom-fetch/src/gen/pets/pets.faker.tsis excluded by!**/gen/**samples/svelte-query/custom-fetch/src/gen/pets/pets.faker.tsis excluded by!**/gen/**samples/svelte-query/v6-custom-fetch/src/gen/pets/pets.faker.tsis excluded by!**/gen/**samples/swr-with-zod/src/gen/endpoints/pets/pets.faker.tsis excluded by!**/gen/**samples/vue-query/custom-fetch/src/gen/pets/pets.faker.tsis excluded by!**/gen/**
📒 Files selected for processing (99)
docs/content/docs/guides/client-with-zod.mdxdocs/content/docs/guides/msw.mdxdocs/content/docs/reference/configuration/output.mdxdocs/content/docs/reference/integration.mdxdocs/content/docs/versions/v8.mdxpackages/angular/src/http-client.test.tspackages/angular/src/http-resource.test.tspackages/core/src/test-utils/context.tspackages/core/src/test-utils/split-modes.tspackages/core/src/types.tspackages/core/src/utils/assertion.tspackages/core/src/utils/file-extensions.tspackages/core/src/writers/mock-outputs.tspackages/core/src/writers/single-mode.tspackages/core/src/writers/split-mode.tspackages/core/src/writers/split-tags-mode.tspackages/core/src/writers/tags-mode.tspackages/core/src/writers/target-tags.tspackages/core/src/writers/target.tspackages/hono/src/index.tspackages/mcp/src/index.tspackages/mock/src/delay.tspackages/mock/src/faker/getters/combine.test.tspackages/mock/src/faker/index.test.tspackages/mock/src/faker/index.tspackages/mock/src/index.tspackages/mock/src/msw/index.test.tspackages/mock/src/msw/index.tspackages/orval/src/api.tspackages/orval/src/bin/orval.tspackages/orval/src/client.tspackages/orval/src/utils/options.tspackages/orval/src/write-specs.tspackages/solid-start/src/index.test.tssamples/angular-app/orval.config.tssamples/angular-query/orval.config.tssamples/hono/hono-with-fetch-client/__snapshots__/next-app/pets/pets.faker.tssamples/next-app-with-fetch/__snapshots__/pets/pets.faker.tssamples/react-app-with-swr/basic/__snapshots__/endpoints/petstoreFromFileSpecWithTransformer.faker.tssamples/react-app-with-swr/basic/src/api/endpoints/petstoreFromFileSpecWithTransformer.faker.tssamples/react-app-with-swr/fetch-client/__snapshots__/endpoints/swaggerPetstore.faker.tssamples/react-app-with-swr/fetch-client/src/api/endpoints/swaggerPetstore.faker.tssamples/react-app/__snapshots__/endpoints/petstoreFromFileSpecWithTransformer.faker.tssamples/react-app/src/api/endpoints/petstoreFromFileSpecWithTransformer.faker.tssamples/react-query/basic/__snapshots__/endpoints/petstoreFromFileSpecWithTransformer.faker.tssamples/react-query/basic/src/api/endpoints/petstoreFromFileSpecWithTransformer.faker.tssamples/react-query/custom-fetch/__snapshots__/pets/pets.faker.tssamples/solid-start/basic/src/api/endpoints/petstore.faker.tssamples/svelte-query/basic/__snapshots__/endpoints/petstoreFromFileSpecWithTransformer.faker.tssamples/svelte-query/basic/src/api/endpoints/petstoreFromFileSpecWithTransformer.faker.tssamples/svelte-query/custom-fetch/__snapshots__/pets/pets.faker.tssamples/svelte-query/v6-custom-fetch/__snapshots__/pets/pets.faker.tssamples/swr-with-zod/__snapshots__/endpoints/pets/pets.faker.tssamples/vue-query/custom-fetch/__snapshots__/pets/pets.faker.tssamples/vue-query/vue-query-basic/__snapshots__/endpoints/petstoreFromFileSpecWithTransformer.faker.tssamples/vue-query/vue-query-basic/src/api/endpoints/petstoreFromFileSpecWithTransformer.faker.tsskills/orval/SKILL.mdskills/orval/advanced-config.mdskills/orval/angular.mdskills/orval/hono.mdskills/orval/mocking-msw.mdskills/orval/solid-start.mdskills/orval/tooling-workflow.mdtests/__snapshots__/angular/split/endpoints.faker.tstests/__snapshots__/angular/tags-split/health/health.faker.tstests/__snapshots__/angular/tags-split/pets/pets.faker.tstests/__snapshots__/axios/petstore-tags-split-mutator/health/health.faker.tstests/__snapshots__/axios/petstore-tags-split-mutator/pets/pets.faker.tstests/__snapshots__/axios/petstore-tags-split/health/health.faker.tstests/__snapshots__/axios/petstore-tags-split/pets/pets.faker.tstests/__snapshots__/axios/split/endpoints.faker.tstests/__snapshots__/default/issue-2998/documents/documents.faker.tstests/__snapshots__/default/issue-2998/requests/requests.faker.tstests/__snapshots__/default/override-mock/endpoints.faker.tstests/__snapshots__/fetch/petstore-tags-split/health/health.faker.tstests/__snapshots__/fetch/petstore-tags-split/pets/pets.faker.tstests/__snapshots__/fetch/split/endpoints.faker.tstests/__snapshots__/mock/petstore-tags-split/health/health.faker.tstests/__snapshots__/mock/petstore-tags-split/pets/pets.faker.tstests/__snapshots__/mock/split/endpoints.faker.tstests/__snapshots__/react-query/importFromSubdirectory/endpoints.faker.tstests/__snapshots__/react-query/petstore-tags-split/health/health.faker.tstests/__snapshots__/react-query/petstore-tags-split/pets/pets.faker.tstests/__snapshots__/react-query/split/endpoints.faker.tstests/__snapshots__/svelte-query/petstore-tags-split/health/health.faker.tstests/__snapshots__/svelte-query/petstore-tags-split/pets/pets.faker.tstests/__snapshots__/svelte-query/split/endpoints.faker.tstests/__snapshots__/swr/petstore-tags-split/health/health.faker.tstests/__snapshots__/swr/petstore-tags-split/pets/pets.faker.tstests/__snapshots__/swr/split/endpoints.faker.tstests/__snapshots__/vue-query/petstore-tags-split/health/health.faker.tstests/__snapshots__/vue-query/petstore-tags-split/pets/pets.faker.tstests/__snapshots__/vue-query/split/endpoints.faker.tstests/__snapshots__/zod/petstore-tags-split/pets/pets.faker.tstests/__snapshots__/zod/split/endpoints.faker.tstests/configs/default.config.tstests/configs/mock.config.tstests/configs/react-query.config.tstests/configs/swr.config.ts
💤 Files with no reviewable changes (3)
- packages/mcp/src/index.ts
- packages/hono/src/index.ts
- packages/orval/src/api.ts
✅ Files skipped from review due to trivial changes (52)
- packages/core/src/test-utils/context.ts
- skills/orval/solid-start.md
- skills/orval/angular.md
- docs/content/docs/versions/v8.mdx
- skills/orval/tooling-workflow.md
- tests/snapshots/react-query/importFromSubdirectory/endpoints.faker.ts
- packages/mock/src/faker/getters/combine.test.ts
- docs/content/docs/reference/integration.mdx
- tests/snapshots/angular/tags-split/health/health.faker.ts
- samples/react-app-with-swr/basic/snapshots/endpoints/petstoreFromFileSpecWithTransformer.faker.ts
- tests/snapshots/default/issue-2998/documents/documents.faker.ts
- tests/snapshots/react-query/petstore-tags-split/health/health.faker.ts
- samples/react-app/src/api/endpoints/petstoreFromFileSpecWithTransformer.faker.ts
- tests/snapshots/mock/petstore-tags-split/health/health.faker.ts
- skills/orval/hono.md
- samples/react-app-with-swr/basic/src/api/endpoints/petstoreFromFileSpecWithTransformer.faker.ts
- samples/react-app-with-swr/fetch-client/snapshots/endpoints/swaggerPetstore.faker.ts
- tests/snapshots/fetch/petstore-tags-split/health/health.faker.ts
- packages/orval/src/bin/orval.ts
- samples/react-app/snapshots/endpoints/petstoreFromFileSpecWithTransformer.faker.ts
- tests/snapshots/fetch/petstore-tags-split/pets/pets.faker.ts
- tests/snapshots/fetch/split/endpoints.faker.ts
- tests/snapshots/vue-query/petstore-tags-split/pets/pets.faker.ts
- skills/orval/advanced-config.md
- skills/orval/mocking-msw.md
- tests/snapshots/swr/petstore-tags-split/pets/pets.faker.ts
- tests/snapshots/react-query/split/endpoints.faker.ts
- tests/snapshots/react-query/petstore-tags-split/pets/pets.faker.ts
- tests/snapshots/svelte-query/split/endpoints.faker.ts
- docs/content/docs/reference/configuration/output.mdx
- samples/svelte-query/basic/src/api/endpoints/petstoreFromFileSpecWithTransformer.faker.ts
- samples/react-query/custom-fetch/snapshots/pets/pets.faker.ts
- tests/snapshots/default/override-mock/endpoints.faker.ts
- tests/snapshots/axios/petstore-tags-split/health/health.faker.ts
- tests/snapshots/axios/petstore-tags-split/pets/pets.faker.ts
- tests/snapshots/vue-query/split/endpoints.faker.ts
- samples/react-query/basic/snapshots/endpoints/petstoreFromFileSpecWithTransformer.faker.ts
- samples/svelte-query/v6-custom-fetch/snapshots/pets/pets.faker.ts
- samples/vue-query/custom-fetch/snapshots/pets/pets.faker.ts
- tests/snapshots/zod/petstore-tags-split/pets/pets.faker.ts
- samples/react-app-with-swr/fetch-client/src/api/endpoints/swaggerPetstore.faker.ts
- tests/snapshots/axios/petstore-tags-split-mutator/pets/pets.faker.ts
- tests/snapshots/zod/split/endpoints.faker.ts
- tests/snapshots/mock/split/endpoints.faker.ts
- tests/snapshots/default/issue-2998/requests/requests.faker.ts
- tests/snapshots/mock/petstore-tags-split/pets/pets.faker.ts
- samples/svelte-query/custom-fetch/snapshots/pets/pets.faker.ts
- tests/snapshots/swr/split/endpoints.faker.ts
- samples/swr-with-zod/snapshots/endpoints/pets/pets.faker.ts
- skills/orval/SKILL.md
- samples/next-app-with-fetch/snapshots/pets/pets.faker.ts
- tests/snapshots/svelte-query/petstore-tags-split/pets/pets.faker.ts
The index-based pairing of mockOutputs to generators was fragile — mockOutputs are accumulated by type insertion order in target.ts, which may not match the user's generator array order. Now all four writer modes (single, split, tags, tags-split) consistently use .find() by type to match each mockOutput to its generator entry. Also adds a runtime TypeError when mock.generators is missing or not an array, preventing opaque crashes from malformed configs.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
packages/core/src/writers/split-tags-mode.ts (1)
49-53:⚠️ Potential issue | 🟠 Major | ⚡ Quick winReject function mock generators before filtering them out.
This mode still accepts
output.mock.generatorsfrom normalization, but this filter silently removes everyClientMockBuilder. In tags-split mode that turns a supported config shape into a no-op: no per-tag mock files and no index files are written. The PR behavior should fail fast here instead.🔧 Suggested guard
+ if (output.mock.generators.some(isFunction)) { + throw new Error( + 'Function mock generators are not supported in tags-split mode. Use typed generators (e.g. { type: "msw" } or { type: "faker" }).', + ); + } + const generatorEntries = output.mock.generators.filter( (g): g is GlobalMockOptions => !isFunction(g), );🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/core/src/writers/split-tags-mode.ts` around lines 49 - 53, Reject function-type mock generators early instead of silently filtering them out: in split-tags-mode, inspect output.mock.generators for any entries where isFunction(g) is true (these represent ClientMockBuilder/function generators) and throw a clear error explaining that tags-split mode does not support function mock generators. Keep the existing filter that produces generatorEntries (const generatorEntries = output.mock.generators.filter((g): g is GlobalMockOptions => !isFunction(g))), but add a pre-check that iterates output.mock.generators, detects any function entries, and raises a validation/throw with context (mentioning tags-split mode and ClientMockBuilder) so the PR fails fast rather than becoming a no-op.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/core/src/writers/split-mode.ts`:
- Around line 174-179: The loop over mockOutputs ignores function-based mocks
because the find only matches typed GlobalMockOptions; update the logic in
split-mode.ts inside the for (const mockOutput of mockOutputs) loop to also
detect and handle function generators from output.mock.generators (use
isFunction to find them) when entry === undefined: if a function generator
exists, treat it as the source (invoke it or derive its result the same way
normalizeOptions would) and proceed to emit the mock file, otherwise fail-fast
with a clear error; reference the variables entry, output.mock.generators,
isFunction, GlobalMockOptions so the change is applied where the current
typed-only lookup occurs.
---
Duplicate comments:
In `@packages/core/src/writers/split-tags-mode.ts`:
- Around line 49-53: Reject function-type mock generators early instead of
silently filtering them out: in split-tags-mode, inspect output.mock.generators
for any entries where isFunction(g) is true (these represent
ClientMockBuilder/function generators) and throw a clear error explaining that
tags-split mode does not support function mock generators. Keep the existing
filter that produces generatorEntries (const generatorEntries =
output.mock.generators.filter((g): g is GlobalMockOptions => !isFunction(g))),
but add a pre-check that iterates output.mock.generators, detects any function
entries, and raises a validation/throw with context (mentioning tags-split mode
and ClientMockBuilder) so the PR fails fast rather than becoming a no-op.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 158e927c-bbd6-45e0-b9b9-d8877f924050
📒 Files selected for processing (5)
docs/content/docs/guides/msw.mdxpackages/core/src/types.tspackages/core/src/writers/split-mode.tspackages/core/src/writers/split-tags-mode.tspackages/orval/src/utils/options.ts
✅ Files skipped from review due to trivial changes (1)
- docs/content/docs/guides/msw.mdx
| for (const mockOutput of mockOutputs) { | ||
| const entry = output.mock.generators.find( | ||
| (g): g is GlobalMockOptions => | ||
| !isFunction(g) && g.type === mockOutput.type, | ||
| ); | ||
| if (!entry) continue; |
There was a problem hiding this comment.
Don't silently drop mock: fn in split mode.
normalizeOptions still normalizes a function-based mock config into output.mock.generators, but this lookup only matches typed entries. With mock: () => ..., entry is always undefined, so split mode emits no mock file instead of preserving the old behavior or failing fast.
🔧 Minimal safeguard
+ if (output.mock.generators.some(isFunction)) {
+ throw new Error(
+ 'Function mock generators are not supported in split mode. Use typed generators (e.g. { type: "msw" } or { type: "faker" }).',
+ );
+ }
+
const mockPaths: string[] = [];
for (const mockOutput of mockOutputs) {
const entry = output.mock.generators.find(
(g): g is GlobalMockOptions =>
!isFunction(g) && g.type === mockOutput.type,🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/core/src/writers/split-mode.ts` around lines 174 - 179, The loop
over mockOutputs ignores function-based mocks because the find only matches
typed GlobalMockOptions; update the logic in split-mode.ts inside the for (const
mockOutput of mockOutputs) loop to also detect and handle function generators
from output.mock.generators (use isFunction to find them) when entry ===
undefined: if a function generator exists, treat it as the source (invoke it or
derive its result the same way normalizeOptions would) and proceed to emit the
mock file, otherwise fail-fast with a clear error; reference the variables
entry, output.mock.generators, isFunction, GlobalMockOptions so the change is
applied where the current typed-only lookup occurs.
Adds a pre-check before filtering generators so that function-based entries (ClientMockBuilder) cause a clear error instead of being silently dropped.
|
@melloware Ok now I'm done. The rabbit had more to say. |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/core/src/writers/split-tags-mode.ts (1)
254-259: 💤 Low valueConsider using
generatorEntriesinstead of re-filtering.Since lines 49-56 now throw if any function generators exist, the
!isFunction(g)check here is redundant. Using the already-filteredgeneratorEntrieswould be cleaner.♻️ Suggested simplification
for (const mockOutput of mockOutputs) { - const entry = output.mock.generators.find( - (g): g is GlobalMockOptions => - !isFunction(g) && g.type === mockOutput.type, - ); + const entry = generatorEntries.find( + (g) => g.type === mockOutput.type, + ); if (!entry) continue;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/core/src/writers/split-tags-mode.ts` around lines 254 - 259, The loop is re-filtering output.mock.generators with a redundant !isFunction check; replace the find over output.mock.generators with a lookup over the already-filtered generatorEntries (which contain only GlobalMockOptions) to simplify and avoid duplicate filtering—use generatorEntries.find(g => g.type === mockOutput.type) (referencing mockOutputs, generatorEntries, output.mock.generators, and isFunction) and remove the redundant type guard/continuation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@packages/core/src/writers/split-tags-mode.ts`:
- Around line 254-259: The loop is re-filtering output.mock.generators with a
redundant !isFunction check; replace the find over output.mock.generators with a
lookup over the already-filtered generatorEntries (which contain only
GlobalMockOptions) to simplify and avoid duplicate filtering—use
generatorEntries.find(g => g.type === mockOutput.type) (referencing mockOutputs,
generatorEntries, output.mock.generators, and isFunction) and remove the
redundant type guard/continuation.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 439b74e4-6020-46d9-9ff8-8cd9902acb32
📒 Files selected for processing (1)
packages/core/src/writers/split-tags-mode.ts
|
Wild, thank you! |
|
This is a great change. |
|
Looks awesome! Thank you so much Looking forward to the release! |
|
Thanks again folks! @melloware Do you have an estimate for when |
|
,I can probably do it today |
Overview
Fix #1832
Supersedes #3398.
Extends
output.mockto accept a multi-generator configuration. Each entry produces its own output file (<filename>.msw.ts,<filename>.faker.ts, etc.), making MSW and Faker first-class peer generators rather than a single toggle with flags.The
generateHandlers: falseworkaround introduced in #3398 is removed — the same intent is now expressed by including or omitting the appropriate generator entry.Usage
Shorthand — emit both MSW handlers and Faker factories:
Produces
endpoints.msw.tsandendpoints.faker.ts.Explicit — MSW only:
Explicit — Faker only (replaces
generateHandlers: false):Output contains only response factories — no MSW import, no handler functions, no aggregated array:
Both generators with
indexMockFiles:Emits one root-level index file per generator entry:
Changes
output.mocknow acceptsboolean | { generators: [...], indexMockFiles?: boolean } | Function.GlobalMockOptionsis now a discriminated union ofMswMockOptions | FakerMockOptions, narrowable viamock.type.OutputMockTypeenum ('msw' | 'faker') and type guardsisMswMock/isFakerMockare exported from@orval/core.mock: trueshorthand normalizes to both{ type: 'msw' }and{ type: 'faker' }generators with defaults.generateHandlersis removed fromGlobalMockOptions.indexMockFilesmoves from inside the generator options into themockwrapper object (its natural home as a collection-level concern).mock.generatorsand emit one file per entry; MSW and Faker files are independent artifacts.Migration
Summary by CodeRabbit
New Features
Documentation
Samples